package com.example.ai.model.viewmodel

import android.util.Log
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.launch
import java.net.SocketException
import java.util.concurrent.ConcurrentHashMap
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * Created by lijinxi on 2024/3/13.
 * @Description:
 */
abstract class BaseViewModel : ViewModel() {
    private val tag: String
        get() = this::class.java.simpleName

    //网络错误
    protected val _netWorkError = mutableStateOf(false)

    var netWorkError = _netWorkError
        private set

    fun resetNetworkError() {
        _netWorkError.value = false
    }

    private val loadStatusMap = ConcurrentHashMap<String, Boolean>()

    private fun String.isLoading(): Boolean {
        return loadStatusMap.getOrDefault(this, false)
    }

    private fun String.start() {
        loadStatusMap[this] = true
    }

    private fun String.end() {
        loadStatusMap[this] = false
    }

    private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception ->
        if (exception.message?.contains("network") == true) {
            _netWorkError.value = true
        }
        Log.e(
            tag, "CoroutineExceptionHandler got ${exception.message}.",
            Throwable(exception)
        )
    }

    private fun CoroutineScope.safeLaunch(
        context: CoroutineContext = EmptyCoroutineContext,
        start: CoroutineStart = CoroutineStart.DEFAULT,
        block: suspend CoroutineScope.() -> Unit
    ) = this.launch(context + coroutineExceptionHandler, start, block)


    protected fun safeRequest(path: String, block: suspend CoroutineScope.() -> Unit) {
        viewModelScope.safeLaunch {
            if (path.isLoading()) return@safeLaunch
            path.start()
            try {
                //否则不能捕获异常, 异常会继续传递
                block.invoke(this)
            } catch (e: Exception) {
                Log.e(tag, "request error: $path", Throwable(e.message))
            } finally {
                path.end()
            }
        }
    }
}